﻿using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace WholeSlideImageLibrary
{
    public sealed class WholeSlideImageReader
    {
        private readonly IImageIdentifier[] _formats;

        public WholeSlideImageReader(IEnumerable<IImageIdentifier> formats)
        {
            if (formats is null)
            {
                throw new ArgumentNullException(nameof(formats));
            }

            _formats = formats.ToArray();
        }


        public async Task<(ImageSourceType Type, IImageIdentifier? Identifier)> IdentifyAsync(FileSourceInfo fileInfo, CancellationToken cancellationToken = default)
        {
            if (fileInfo is null)
            {
                throw new ArgumentNullException(nameof(fileInfo));
            }

            // 最大HeaderSize
            int headerSize = 0;
            foreach (IImageIdentifier? format in _formats)
            {
                int size = format.HeaderSize;
                if (size > headerSize)
                {
                    headerSize = size;
                }
            }

            // 准备Reader
            byte[]? buffer = null;
            FileSourceReader? reader = null;
            try
            {
                reader = await fileInfo.OpenAsync(cancellationToken).ConfigureAwait(false);

                // 读取Header
                Memory<byte> header = default;
                if (headerSize != 0)
                {
                    buffer = ArrayPool<byte>.Shared.Rent(headerSize);
                    int bytesRead = await reader.ReadAsync(0, buffer.AsMemory(0, headerSize), cancellationToken).ConfigureAwait(false);
                    header = buffer.AsMemory(0, bytesRead);
                }

                // 进行检测
                foreach (IImageIdentifier? format in _formats)
                {
                    try
                    {
                        ImageSourceType type = await format.IdentifyAsync(fileInfo, reader, header, cancellationToken).ConfigureAwait(false);

                        if (type != ImageSourceType.None)
                        {
                            return (Type: type, Identifier: format);
                        }
                    }
                    catch (Exception)
                    {
                        continue;
                    }
                }
            }
            finally
            {
                if (!(buffer is null))
                {
                    ArrayPool<byte>.Shared.Return(buffer);
                }
                if (!(reader is null))
                {
                    await reader.DisposeAsync().ConfigureAwait(false);
                }
            }

            return (Type: ImageSourceType.None, Identifier: null);
        }

        public Task<(ImageSourceType Type, IImageIdentifier? Identifier)> IdentifyAsync(DirectorySourceInfo directoryInfo)
        {
            throw new NotImplementedException();
        }

        public async Task<WholeSlideImageShim?> OpenSingleImageAsync(FileSourceInfo fileInfo, CancellationToken cancellationToken = default)
        {
            if (fileInfo is null)
            {
                throw new ArgumentNullException(nameof(fileInfo));
            }

            // 最大HeaderSize
            int headerSize = 0;
            foreach (IImageIdentifier? format in _formats)
            {
                int size = format.HeaderSize;
                if (size > headerSize)
                {
                    headerSize = size;
                }
            }

            // 准备Reader
            byte[]? buffer = null;
            FileSourceReader? reader = null;
            try
            {
                reader = await fileInfo.OpenAsync(cancellationToken).ConfigureAwait(false);

                // 读取Header
                Memory<byte> header = default;
                if (headerSize != 0)
                {
                    buffer = ArrayPool<byte>.Shared.Rent(headerSize);
                    int bytesRead = await reader.ReadAsync(0, buffer.AsMemory(0, headerSize), cancellationToken).ConfigureAwait(false);
                    header = buffer.AsMemory(0, bytesRead);
                }

                // 进行检测
                foreach (IImageIdentifier? format in _formats)
                {
                    try
                    {
                        ImageSourceType type = await format.IdentifyAsync(fileInfo, reader, header, cancellationToken).ConfigureAwait(false);

                        if (type == ImageSourceType.SingleImage)
                        {
                            WholeSlideImage? image = await format.OpenSingleImageAsync(fileInfo, reader, cancellationToken).ConfigureAwait(false);
                            if (!(image is null))
                            {
                                return WholeSlideImageShim.Wrap(image);
                            }
                        }
                    }
                    catch (Exception)
                    {
                        continue;
                    }
                }
            }
            finally
            {
                if (!(buffer is null))
                {
                    ArrayPool<byte>.Shared.Return(buffer);
                }
                if (!(reader is null))
                {
                    await reader.DisposeAsync().ConfigureAwait(false);
                }
            }

            return null;
        }

        public Task<WholeSlideImageShim?> OpenSingleImageAsync(DirectorySourceInfo directoryInfo)
        {
            throw new NotImplementedException();
        }

    }
}
